package erp_services

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
	"strconv"
	"sync"
	"time"
	"xiehui-service/app/common/request"
	"xiehui-service/app/services/types"
	"xiehui-service/global"

	"go.uber.org/zap"
)

type autoDispatchService struct {
}

type ApiResponse struct {
	Code    int         `json:"code"`           // 响应状态码
	Message string      `json:"message"`        // 响应消息
	Data    interface{} `json:"data,omitempty"` // 响应数据，可以为空
	Traceid string      `json:"traceid"`
}

type WsInfo struct {
	Type string      `json:"type"`
	Info interface{} `json:"info"`
}

type NextPlan struct {
	Plan     types.Plan `json:"plan"`
	Vid      int        `json:"vId"`
	Timeleft int        `json:"timeLeft"`
	MixerNo  int        `json:"mixerNo"`
}

type QueueVehicle struct {
	VehicleID          int           `json:"vehicle_id"`
	VehicleNo          string        `json:"vehicle_no"`
	VehicleContacts    string        `json:"vehicle_contacts"`
	VehicleType        int           `json:"vehicle_type"`
	VehicleStatus      int           `json:"vehicle_status"`
	DispatchStatus     int           `json:"dispatch_status"`
	DispatchStatusText string        `json:"dispatch_status_text"`
	MaxCapacity        int           `json:"max_capacity"`
	RemainQuantity     float64       `json:"remain_quantity"`
	ReturnQuantity     float64       `json:"return_quantity"`
	IsOff              int           `json:"is_off"`
	Sort               int           `json:"sort"`
	Dispatchs          []interface{} `json:"dispatchs"`
	Deliveries         []interface{} `json:"deliveries"`
}

const (
	TASK_ADD            = "sd_task_add"            //开启新调度
	TASK_DEL            = "sd_task_del"            //结束调度
	TASK_STOP_ALL       = "sd_stop_all"            //全部停止
	TASK_EXEC           = "sd_produce_immediate"   //立刻执行
	TASK_PUMP_SET       = "sd_task_pump_setup"     //配置任务单速率
	TASK_PAUSE_QUANTITY = "sd_task_pause_quantity" //配置暂停方量
	TASK_REBUILD_PLAN   = "sd_task_rebuild_plan"   //重新生成计划
)
const apiJwtCacheKeyPre = "apiJwt:token"
const LeftSeconds = 30

var AutoDispatchService = new(autoDispatchService)

// 查询开启自动调度的任务单
func (autoDispatchService *autoDispatchService) AutoHandle(param request.HandleArgs) (ret string, err error) {
	fmt.Println(param.Action, "OK")

	switch param.Action {
	case TASK_ADD:
		op := "开启自动调度"
		task_id := uint(param.Args["task_id"].(float64))
		OrderTaskService.SetAutoDispatch(task_id, 1)
		order, err2 := OrderTaskService.GetOrderTaskInfo(request.List{Id: int(task_id)})
		if err2 != nil {
			err = errors.New("未查询到任务单信息")
			return
		}
		content := fmt.Sprintf("任务单【%s】%s", order.TaskNo, op)
		AutoDispatchService.WriteOpLog(op, content)

		// 重新生成计划
		OrderAutoDispatchPlanService.GenerateSDPlan()
		return
	case TASK_DEL:
		op := "关闭自动调度"
		// 判断是否配置过
		task_id := uint(param.Args["task_id"].(float64))
		order, err2 := OrderTaskService.GetOrderTaskInfo(request.List{Id: int(task_id)})
		if err2 != nil {
			err = errors.New("未查询到任务单信息")
			return
		}
		OrderTaskService.SetAutoDispatch(task_id, 0)
		content := fmt.Sprintf("任务单【%s】%s", order.TaskNo, op)
		AutoDispatchService.WriteOpLog(op, content)

		// 重新生成计划
		OrderAutoDispatchPlanService.GenerateSDPlan()
		return
	case TASK_STOP_ALL:
		op := "【全部】停止自动调度"
		OrderTaskService.CloseAllDispatch()
		content := fmt.Sprintf("任务单 %s", op)
		AutoDispatchService.WriteOpLog(op, content)

		// 清空排车计划
		_, e := OrderAutoDispatchPlanService.CancelPlan()
		if e != nil {
			global.App.Log.Error(e.Error())
		}
		return
	case TASK_PAUSE_QUANTITY:
		op := "设置暂停方量"
		task_id := uint(param.Args["task_id"].(float64))
		pause_quantity, ok := param.Args["pause_quantity"].(string)
		if ok {
			pause_quantity_float, err1 := strconv.ParseFloat(pause_quantity, 64)
			if err1 != nil {
				err = errors.New("暂停方量设置错误")
				return
			}
			if pause_quantity_float < 0 {
				err = errors.New("暂停方量必须大于0")
				return
			}

			order, err2 := OrderTaskService.GetOrderTaskInfo(request.List{Id: int(task_id)})
			if err2 != nil {
				err = errors.New("未查询到任务单信息")
				return
			}
			if pause_quantity_float > order.PlanQuantity {
				err = errors.New("暂停方量不能大于计划方量")
				return
			}

			OrderTaskService.SetPauseQuantity(task_id, pause_quantity_float)
			content := fmt.Sprintf("任务单【%s】 %s %.2f", order.TaskNo, op, pause_quantity_float)
			AutoDispatchService.WriteOpLog(op, content)

			// 重新生成计划
			OrderAutoDispatchPlanService.GenerateSDPlan()
		}
		return
	case TASK_EXEC:
		log.Println("===>>>收到立即执行的指令")
		op := "立即执行自动调度"
		plan_id := uint(param.Args["plan_id"].(float64))
		content := fmt.Sprintf("任务单【%d】%s", plan_id, op)
		AutoDispatchService.WriteOpLog(op, content)

		planWillExec := fmt.Sprintf("planWillExec:%d", plan_id)
		exist := global.App.Redis.Exists(context.Background(), planWillExec).Val()
		log.Println("===>>>收到立即执行的指令:planWillExec:", planWillExec, exist)
		if exist == 1 {
			var nextPlan NextPlan
			err1 := json.Unmarshal([]byte(global.App.Redis.Get(context.Background(), planWillExec).Val()), &nextPlan)
			log.Println("===>>>收到立即执行的指令:nextPlan:", nextPlan)
			if err1 != nil {
				err = errors.New("立即执行自动调度,解析执行计划信息失败")
				global.App.Log.Error(err.Error())
				return
			}

			autoDispatchService.ExecPlan(nextPlan.Plan, nextPlan.Vid, nextPlan.MixerNo)

		} else {
			global.App.Log.Error("立即执行自动调度, 未查询到缓存信息")
		}

		return
	case TASK_PUMP_SET:
		op := "配置任务单速率"
		task_id := uint(param.Args["task_id"].(float64))
		auto_ratio := int(param.Args["auto_ratio"].(float64))

		var ratio_str string
		if auto_ratio == 50 {
			ratio_str = "0.5倍速"
		} else if auto_ratio == 200 {
			ratio_str = "2倍速"
		} else {
			ratio_str = "默认速度"
		}

		order, err1 := OrderTaskService.GetOrderTaskInfo(request.List{Id: int(task_id)})
		if err1 != nil {
			err = errors.New("配置任务单速率,未查询到任务单信息")
			return
		}

		content := fmt.Sprintf("任务单【%s】%s, %s", order.TaskNo, op, ratio_str)
		AutoDispatchService.WriteOpLog(op, content)

		_, err2 := OrderTaskService.SetAutoRatio(task_id, auto_ratio)
		if err2 != nil {
			err = errors.New("配置任务单速率失败")
			global.App.Log.Error(err.Error())
			return
		}
		// 重新生成计划
		OrderAutoDispatchPlanService.GenerateSDPlan()

		global.App.Log.Info("配置任务单速率", zap.Any("content:", content))
		return
	case TASK_REBUILD_PLAN:
		// 重新生成计划
		OrderAutoDispatchPlanService.GenerateSDPlan()
		return
	default:
		err = errors.New(param.Action + " 操作不存在")
	}
	return
}

// 获取调度计划
func (autoDispatchService *autoDispatchService) GetAutoPlans() (rows []types.Plan, err error) {
	err = global.App.DB.Table("order_auto_dispatch_plan").Select("`order_auto_dispatch_plan`.id, `order_auto_dispatch_plan`.task_id, `order_auto_dispatch_plan`.start_time, t1.project_name, t1.build_position, t1.project_sub_name, t1.concrete_category, t1.count_vehicle, t1.concrete_quantity, t1.delivery_quantity, t1.task_no").Joins("LEFT JOIN `order_task` t1 ON t1.id = `order_auto_dispatch_plan`.task_id").Where("`order_auto_dispatch_plan`.`current` = 1 AND `order_auto_dispatch_plan`.`state` = 0").Scan(&rows).Error
	if err != nil {
		if err.Error() == "record not found" {
			err = errors.New("数据不存在")
		}
	}
	return
}

// erp登录
func (autoDispatchService *autoDispatchService) HttpApiLogin() (data map[string]interface{}, err error) {
	// 构建请求Body体
	requestBody := fmt.Sprintf("{\"username\": \"%s\", \"password\": \"%s\"}", global.App.Config.Erp.Username, global.App.Config.Erp.Pwd)

	// 创建一个新的HTTP请求对象
	req, err := http.NewRequest("POST", global.App.Config.Erp.AppUrl+"/api/employee/login", bytes.NewBufferString(requestBody))
	if err != nil {
		log.Fatalln(err)
	}

	req.Header.Set("Content-Type", "application/json")

	// 发起HTTP请求
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		log.Fatalln(err)
	}
	defer resp.Body.Close()

	// 读取响应结果
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Fatalln(err)
	}

	var ret ApiResponse
	if err := json.Unmarshal(body, &ret); err != nil {
		global.App.Log.Error(err.Error())
	}

	data, ok := ret.Data.(map[string]interface{})
	if !ok {
		// fmt.Print("===>>>", data["access_token"].(string))
		err = errors.New("获取Api调用token失败")
	}
	return
}

// 调用排车接口
func (autoDispatchService *autoDispatchService) HttpDispatch(args request.DispatchArgs) (ret ApiResponse, err error) {
	var jwtToken string
	cacheKey := apiJwtCacheKeyPre

	exist := global.App.Redis.Exists(context.Background(), cacheKey).Val()
	if exist == 1 {
		jwtToken = global.App.Redis.Get(context.Background(), cacheKey).Val()
	} else {
		res, err := AutoDispatchService.HttpApiLogin()
		if err == nil {
			jwtToken = res["access_token"].(string)
			global.App.Redis.Set(context.Background(), cacheKey, jwtToken, time.Second*3600)
		}
	}

	// 构建请求Body体
	requestBody, err := json.Marshal(args)
	if err != nil {
		log.Fatalln(err)
	}
	// 创建一个新的HTTP请求对象
	req, err := http.NewRequest("POST", global.App.Config.Erp.AppUrl+"/api/production/dispatch/add", bytes.NewBufferString(string(requestBody)))
	if err != nil {
		log.Fatalln(err)
	}

	// 在请求头部中设置Token信息
	req.Header.Set("Authorization", fmt.Sprintf(`Bearer %s`, jwtToken))
	req.Header.Set("Content-Type", "application/json")

	// 发起HTTP请求
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		log.Fatalln(err)
	}
	defer resp.Body.Close()

	// 读取响应结果
	body, err := io.ReadAll(resp.Body)
	// fmt.Print("body===>>", string(body))
	if err != nil {
		log.Fatalln(err)
	}

	if err := json.Unmarshal(body, &ret); err != nil {
		global.App.Log.Error(err.Error())
	}
	return
}

// websocket操作
func (autoDispatchService *autoDispatchService) WsOp(opType string, info interface{}) (err error) {
	wsInfo := WsInfo{
		Type: opType,
		Info: info,
	}

	wsInfoJson, err := json.Marshal(wsInfo)
	if err != nil {
		global.App.Log.Error(err.Error())
	}
	var wg sync.WaitGroup
	var mu sync.Mutex

	wg.Add(1)

	go func() {
		defer wg.Done()
		mu.Lock()
		defer mu.Unlock()
		global.App.DispatcherMsgReceiver <- wsInfoJson
	}()
	wg.Wait()

	return
}

// 操作日志
func (autoDispatchService *autoDispatchService) WriteOpLog(op string, content string) (err error) {
	OrderAtuoDispatchLogService.CreateLog(op, content, time.Now())
	return
}

// 立即执行计划
func (autoDispatchService *autoDispatchService) ExecPlan(plan types.Plan, vId int, mixerNo int) (err error) {
	log.Println("立即执行计划===", plan, vId, mixerNo)
	global.App.Log.Info("立即执行计划（param）:", zap.Any("plan:", plan), zap.Any("vId:", vId), zap.Any("mixerNo:", mixerNo))
	vehicleInfo, err := VehicleService.GetVehicle(int(vId))
	if err != nil {
		global.App.Log.Error(err.Error())
		return
	}

	req := request.DispatchArgs{
		TaskID:                   plan.TaskId,
		DeliveryConcreteCategory: plan.ConcreteCategory,
		RemainConcreteCategory:   "",
		VehicleCapacity:          vehicleInfo.MaxCapacity,
		BuildPosition:            plan.BuildPosition,
		Remark:                   "",
		ProjectSubName:           plan.ProjectSubName,
		VehicleID:                vId,
		VehicleNo:                vehicleInfo.VehicleNo,
		VehicleContacts:          "",
		Items: []request.DispatchItem{
			{
				Key:              1,
				MixerNo:          strconv.Itoa(mixerNo),
				ConcreteQuantity: vehicleInfo.MaxCapacity,
				ReturnQuantity:   0,
				MortarQuantity:   0,
				DeliveryQuantity: vehicleInfo.MaxCapacity,
				CountVehicle:     plan.CountVehicle + 1,
				CountQuantity:    plan.DeliveryQuantity + vehicleInfo.MaxCapacity,
				IsWater:          0,
				RemainQuantity:   0,
			},
		},
		IsCancelBefore: 0,
	}

	ret, _ := AutoDispatchService.HttpDispatch(req)
	log.Println("ret====", ret)
	global.App.Log.Info("调用排车接口:", zap.Any("req:", req), zap.Any("ret:", ret))
	if ret.Code == 1000 {

		// 更新计划为执行成功
		_, err1 := OrderAutoDispatchPlanService.SetPlanState(plan.Id, 5)
		if err1 != nil {
			global.App.Log.Error(err1.Error())
		}
		AutoDispatchService.WsOp("dispatch_ok", fmt.Sprintf("请%s号车进入%s号拌台;", req.VehicleNo, req.Items[0].MixerNo))

		content := fmt.Sprintf("倒计时结束，已执行任务单[%d]的排车", req.TaskID)
		AutoDispatchService.WriteOpLog("排车倒计时结束", content)

		content = fmt.Sprintf("将%s车 排到 工程：%s， 部位：%s，安排生产%.2fm³。", req.VehicleNo, plan.ProjectSubName, plan.BuildPosition, vehicleInfo.MaxCapacity)
		AutoDispatchService.WriteOpLog("排车", content)
	} else {
		AutoDispatchService.WsOp("dispatch_fail", fmt.Sprintf("【%d】自动排车失败,原因是:%s;", req.TaskID, ret.Message))
	}
	return
}

// 发送倒计时信息
func (autoDispatchService *autoDispatchService) CountDownInfo(plan types.Plan, vId int, timeLeft int, mixerNo int) (err error) {
	plan_id := plan.Id
	k := fmt.Sprintf("planCountDown:%d", plan_id)
	planWillExec := fmt.Sprintf("planWillExec:%d", plan_id)
	exist := global.App.Redis.Exists(context.Background(), k).Val()
	if exist != 1 {
		global.App.Redis.GetSet(context.Background(), k, 1)
		nextPlan := NextPlan{Plan: plan, Vid: vId, Timeleft: timeLeft, MixerNo: mixerNo}
		jsonBytes, err1 := json.Marshal(nextPlan)

		if err1 != nil {
			err = errors.New("数据处理即将执行的计划失败")
			global.App.Log.Error(err1.Error())
			return
		}
		fmt.Println("string(jsonBytes)===>>>", string(jsonBytes))
		global.App.Redis.Set(context.Background(), planWillExec, string(jsonBytes), time.Second*LeftSeconds)
		content := fmt.Sprintf("任务单【%d】倒计时开始，等待执行排车操作", plan_id)
		AutoDispatchService.WriteOpLog("排车倒计时", content)
	}

	vehicleInfo, err := VehicleService.GetVehicle(int(vId))
	if err != nil {
		global.App.Log.Error(err.Error())
		return
	}
	AutoDispatchService.WsOp("dispatch_handle", map[string]interface{}{
		"second_left":      timeLeft,
		"build_position":   plan.BuildPosition,
		"project_sub_name": plan.ProjectSubName,
		"vehicle_no":       vehicleInfo.VehicleNo,
		"task_id":          plan.TaskId,
		"id":               plan.Id,
	})
	return
}

// erp队列信息
func (autoDispatchService *autoDispatchService) ErpQueueList() (ret ApiResponse, err error) {
	var jwtToken string
	cacheKey := apiJwtCacheKeyPre

	exist := global.App.Redis.Exists(context.Background(), cacheKey).Val()
	if exist == 1 {
		jwtToken = global.App.Redis.Get(context.Background(), cacheKey).Val()
	} else {
		res, err := AutoDispatchService.HttpApiLogin()
		if err == nil {
			jwtToken = res["access_token"].(string)
			global.App.Redis.Set(context.Background(), cacheKey, jwtToken, time.Second*3600)
		}
	}

	// 构建请求Body体
	requestBody := []byte{}
	// 创建一个新的HTTP请求对象
	req, err := http.NewRequest("POST", global.App.Config.Erp.AppUrl+"/api/production/dispatch/queue_list", bytes.NewBufferString(string(requestBody)))
	if err != nil {
		log.Fatalln(err)
	}

	// 在请求头部中设置Token信息
	req.Header.Set("Authorization", fmt.Sprintf(`Bearer %s`, jwtToken))
	req.Header.Set("Content-Type", "application/json")

	// 发起HTTP请求
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		log.Fatalln(err)
	}
	defer resp.Body.Close()

	// 读取响应结果
	body, err := io.ReadAll(resp.Body)
	// fmt.Print("body===>>", string(body))
	if err != nil {
		log.Fatalln(err)
	}

	if err := json.Unmarshal(body, &ret); err != nil {
		global.App.Log.Error(err.Error())
	}
	return
}

// 获取接下来排车车辆
func (autoDispatchService *autoDispatchService) GetQueueFirstCar() (vehicle QueueVehicle, err error) {
	ret, err := AutoDispatchService.ErpQueueList()

	if ret.Code != 1000 {
		global.App.Log.Error("获取队列车辆发生异常")
		return
	}

	data, ok := ret.Data.([]interface{})
	if ok {
		var waitQueue []map[string]interface{}
		for _, item := range data {
			if itemMap, ok := item.(map[string]interface{}); ok {
				t, ok := itemMap["type"] // type=2排队队列
				if ok {
					if t == float64(2) {
						waitQueue = append(waitQueue, itemMap)
					}
				}
			}
		}
		if len(waitQueue) > 0 {
			queues, err1 := OrderDispatchConfigService.GetOrderDispatchConfig(1)
			if err1 != nil {
				err = errors.New("获取全部队列信息错误")
				return
			}

			for i := 0; i < len(queues); i++ {
				queue, err1 := OrderDispatchConfigService.GetOneQueue()
				if err1 != nil {
					err = errors.New("获取队列信息错误")
					return
				}

				for _, item := range waitQueue {
					if queue.ID.ID == uint(item["id"].(float64)) {
						if val, ok := item["vehiclies"].([]interface{}); ok {
							if len(val) > 0 {
								for i := 0; i < len(val); i++ {
									vehicleMap := val[i].(map[string]interface{})
									if vehicleMap["remain_quantity"].(float64) > 0 {
										continue
									}
									vehicle = QueueVehicle{
										VehicleID:          int(vehicleMap["vehicle_id"].(float64)),
										VehicleNo:          vehicleMap["vehicle_no"].(string),
										VehicleContacts:    vehicleMap["vehicle_contacts"].(string),
										VehicleType:        int(vehicleMap["vehicle_type"].(float64)),
										VehicleStatus:      int(vehicleMap["vehicle_status"].(float64)),
										DispatchStatus:     int(vehicleMap["dispatch_status"].(float64)),
										DispatchStatusText: vehicleMap["dispatch_status_text"].(string),
										MaxCapacity:        int(vehicleMap["max_capacity"].(float64)),
										RemainQuantity:     vehicleMap["remain_quantity"].(float64),
										ReturnQuantity:     vehicleMap["return_quantity"].(float64),
										IsOff:              int(vehicleMap["is_off"].(float64)),
										Sort:               int(vehicleMap["sort"].(float64)),
										Dispatchs:          vehicleMap["dispatchs"].([]interface{}),
										Deliveries:         vehicleMap["deliveries"].([]interface{}),
									}
									return
								}
							}
						}
					}
				}
			}
		}
	}

	return
}

// 获取拌台信息
func (autoDispatchService *autoDispatchService) GetMixtable() (mixerNo uint, err error) {
	mixtables, err1 := MixtableService.GetMixtables()
	if err1 != nil {
		err = errors.New("查询拌台信息失败")
	}
	for _, v := range mixtables {
		cnt, err1 := OrderDispatchQueueService.GetMixtableCars(v.ID.ID)
		if err1 != nil {
			err = errors.New("查询拌台车辆信息失败")
		}
		if cnt < 2 {
			mixerNo = v.ID.ID
			break
		}
	}
	return
}
